//
//  HJNetworking.m
//  KaiChat
//
//  Created by lx on 2023/10/16.
//

#import "HJNetworking.h"
#import "HJAppInfo.h"
#import <MBProgressHUD.h>
#import "HJLoadingView.h"
#import "HJAlertController.h"


NSURLSessionDownloadTask * HJDownloadFileWithUrl(NSString *url,void (^progress)(CGFloat value), NSURL *(^destination)(void), void (^complete)(NSError * _Nullable error)) {
    
    NSString *localPath = destination().path;
    if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
        complete(nil);
        return nil;
    }
    
    if (isEmptyString(url)) {
        complete([NSError errorWithCode:-10001 errorReason:@"url错误"]);
        return nil;
    }
 
    AFURLSessionManager *sessionManager = [[AFURLSessionManager alloc] init];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url.URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
    NSURLSessionDownloadTask *task = [sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        dispatch_async_main_queue(^{
            progress(downloadProgress.fractionCompleted);
        });
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return destination();
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        dispatch_async_main_queue(^{
            complete(error);
        });
    }];
    [task resume];
    return task;
}


@interface HJNetworking()

@property (nonatomic, strong) NSArray *showErrorMessageApiArray;
@property (nonatomic, strong) NSArray *notHiddenLoadingMessageApiArray;


@end

@implementation HJNetworking

static HJNetworking *_network = nil;

+ (HJNetworking *)shareNetwork {
    return [[HJNetworking alloc] init];
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_network == nil) {
            _network = [super allocWithZone:zone];
        }
    });
    return _network;
}

- (void)POST:(NSString *)url parameters:(id)parameters success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure {
    [self dataTaskWithMethod:@"POST" urlString:url isJson:NO parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)POSTBodyJSON:(NSString *)url parameters:(nullable id)parameters success:(void (^__nullable)(NSDictionary *responseObject, id data))success failure:(void (^__nullable)(NSError *error))failure {
    [self dataTaskWithMethod:@"POST" urlString:url isJson:YES parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)GET:(NSString *)url parameters:(id)parameters success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure {
    [self dataTaskWithMethod:@"GET" urlString:url isJson:NO parameters:parameters success:^(id _Nullable responseObject) {
        [self handleResponseObject:responseObject url:url success:success];
    } failure:^(NSError *error) {
        [self handleError:error url:url failure:failure];
    }];
}

- (void)uploadImageWithUrl:(NSString *)url
                  fileData:(NSData *)fileData
                   fileKey:(NSString *)fileKey
                  progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
                   success:(void (^)(NSDictionary *responseObject, id data))success
                   failure:(void (^)(NSError *error))failure {
    
    NSString *urlString = [self getRequestUrlWithUrl:url];
    NSDictionary *headers = [self addCommonHeaderWithUrl:urlString];
    TJDetailLog(@"%@ ----- 开始上传", urlString);
    
    [getHTTPSessionManager() POST:urlString parameters:nil headers:headers constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyMMddHHmmss"];
        NSString *fileName =  [NSString stringWithFormat:@"%@.jpeg",[formatter stringFromDate:[NSDate date]]];
        [formData appendPartWithFileData:fileData name:fileKey fileName:fileName mimeType:@"image.jpeg"];
        
    } progress:uploadProgress success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        TJDetailLog(@"%@ ----- responseObject = %@", urlString, responseObject);
        
        [self handleResponseObject:responseObject url:url success:success];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //        if (error.code == NSURLErrorTimedOut) {
        //
        //        }
        TJDetailLog(@"%@ ----- error = %@", urlString, error);
        [self handleError:error url:url failure:failure];
    }];
}

- (void)uploadImageWithObejctKey:(NSString *)obejctKey
                        fileData:(NSData *)fileData
                        progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
                         success:(void (^)(NSDictionary *responseObject, id data))success
                         failure:(void (^)(NSError *error))failure {
    [HJNetworking.shareNetwork GET:@"/v1/upload/url" parameters:@{
        @"object_key": obejctKey
    } success:^(NSDictionary * _Nonnull responseObject, id  _Nonnull data) {
        NSString *urlString = data[@"url"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlString.URL];
        request.HTTPMethod = @"PUT";
        request.HTTPBody = fileData;
        [[getHTTPSessionManager() dataTaskWithRequest:request uploadProgress:uploadProgress downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            if (error) {
                !failure ?: failure(error);
            } else {
                !success ?: success(responseObject, data);
            }
        }] resume];
    } failure:failure];    
}


- (void)dataTaskWithMethod:(NSString *)method
                 urlString:(NSString *)urlString
                    isJson:(BOOL)isJson
                parameters:(nullable id)parameters
                   success:(void (^)(id  _Nullable responseObject))success failure:(void (^)(NSError * error))failure {
    
    NSDate *startDate = [NSDate date];
    NSString *url = [self getRequestUrlWithUrl:urlString];
    NSDictionary *headers = [self addCommonHeaderWithUrl:url];
    AFHTTPSessionManager *sessionManager = isJson ? getBodyJsonHTTPSessionManager() : getHTTPSessionManager();
    NSURLSessionDataTask *dataTask = [sessionManager dataTaskWithHTTPMethod:method URLString:url.encodeUrl parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        TJDetailLog(@"method = %@, urlString = %@, parameters = %@, headers = %@ 耗时 = %.2f \n responseObject = %@", method, url, parameters, headers, [NSDate date].timeIntervalSince1970 - startDate.timeIntervalSince1970, responseObject);
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        TJDetailLog(@"method = %@, urlString = %@, parameters = %@, headers = %@ 耗时 = %.2f \n error = %@", method, url, parameters, headers, [NSDate date].timeIntervalSince1970 - startDate.timeIntervalSince1970, error);
        if (failure) {
            failure(error);
        }
    }];
    [dataTask resume];
}

- (void)handleError:(NSError *)error url:(NSString *)url  failure:(void (^)(NSError * _Nonnull))failure {
    
    NSDictionary *responseObject = [error getAFNOperationFailingURLResponseData];
    if (!responseObject) {
        if (failure) {
            failure(error);
        }
        return;
    }
    
    NSLog(@"error.responseObject = %@", responseObject);
    NSInteger resCode = [responseObject[@"code"] intValue];
    NSString *message = responseObject[@"msg"];
    
    if (resCode == 1301 || resCode == 401) {//token error
        [self tokenError];
        return;
    }
    
    if ([self.showErrorMessageApiArray containsObject:url] && !isEmptyString(message)) {
        [HJHUD showErrorMessage:message];
    }
    
    if (failure) {
        NSMutableDictionary *errorDict = @{}.mutableCopy;
        [errorDict setValue:message forKey:NSLocalizedFailureReasonErrorKey];
        [errorDict setValue:responseObject forKey:@"responseObject"];
        failure([NSError errorWithCode:resCode userInfo:errorDict]);
    }
}

- (void)tokenError {
    [HJHUD hiddenLoading];
    [[NSNotificationCenter defaultCenter] postNotificationName:tokenErrorNotification object:nil userInfo:nil];
    HJUserInfo.isLogin = NO;
    HJUserInfo.token = nil;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(300 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
        [HJAlertController alertInController:getMainController() title:nil message:@"登录已过期,请重新登录" left:nil right:^(HJAlertAction * _Nonnull action) {
            action.title = @"知道了";
            action.titleColor = UIColor.whiteColor;
            action.backgroundColor = UIColor.tj_mainColor;
        }];
    });
}

- (void)handleResponseObject:(NSDictionary *)responseObject url:(NSString *)url success:(void (^)(NSDictionary * _Nonnull, id _Nonnull))success {
    
    if (![self.notHiddenLoadingMessageApiArray containsObject:url] && HJTools.tool.currentHud) {
        [HJHUD hiddenLoading];
        NSLog(@"HJTools.tool.currentHud = %@", HJTools.tool.currentHud);
    }
    
    if (![responseObject isKindOfClass:NSDictionary.class]) return ;
    if (!responseObject.allKeys.count) return;
    
    int code = [responseObject[@"code"] intValue];
    if (code == 0 || code == 200) {
        if (success) {
            success(responseObject, responseObject[@"data"]);
        }
        return;
    }
    
    NSString *message = responseObject[@"msg"];
    if ([self.showErrorMessageApiArray containsObject:url] && !isEmptyString(message)) {
        [HJHUD showErrorMessage:message];
    }
    
    if (code == 1301 || code == 401) {
        [self tokenError];
        return;
    }
}

- (NSString *)getRequestUrlWithUrl:(NSString *)url {
    if ([url containsString:@"http"]) {
        return url;
    } else {
        return [NSString stringWithFormat:@"%@%@", getBaseUrlString(), url];
    }
}

- (NSDictionary *)addCommonHeaderWithUrl:(NSString *)url {
    if (HJUserInfo.isLogin && !isEmptyString(HJUserInfo.token)) {
        return @{
            @"Authorization": HJUserInfo.token
        };
    }
    return nil;
}

- (NSArray *)showErrorMessageApiArray {
    if (!_showErrorMessageApiArray) {
        _showErrorMessageApiArray = @[
            API_login,
            API_register,
            API_emailVerify,
            API_setPassword,
            API_revoked,
            API_createGroup
        ];
    }
    return _showErrorMessageApiArray;
}

- (NSArray *)notHiddenLoadingMessageApiArray {
    if (!_notHiddenLoadingMessageApiArray) {
        _notHiddenLoadingMessageApiArray = @[
            API_createGroup
        ];
    }
    return _notHiddenLoadingMessageApiArray;
}

@end

